package cgs

import (
	"fmt"
	"cgs-server/helper"
	"cgs-server/server"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
	"net/http"
	"os"
	"strings"
	"time"
)

func init() {
	//server.Handle(http.MethodGet, "/api/Cgs/Proj/List", List, server.None)
	//server.Handle(http.MethodPost, "/api/Cgs/Proj/Delete", Delete, server.DeleteScene)
	//server.Handle(http.MethodPost, "/api/Cgs/Proj/ChangeData", ChangeData, server.SaveScene)
	//server.Handle(http.MethodPost, "/api/Cgs/Proj/ChangeName", ChangeName, server.SaveScene)
	//server.Handle(http.MethodPost, "/api/Cgs/Proj/Save", Save, server.SaveScene)
	//server.Handle(http.MethodGet, "/api/Cgs/Proj/Get", Get, server.None)

	//server.Get("/api/Cgs/Proj/List", List, "获取工程列表", server.None)
	//server.Post("/api/Cgs/Proj/Delete", Delete, "删除工程", server.Login)
	//server.Post("/api/Cgs/Proj/ChangeData", ChangeData, "更新工程数据", server.Login)
	//server.Post("/api/Cgs/Proj/ChangeName", ChangeName, "修改工程名称", server.Login)
	//server.Post("/api/Cgs/Proj/Save", Save, "添加或保存工程", server.Login)
	//server.Get("/api/Cgs/Proj/Get", Get, "获取工程", server.None)
}
func List2(w http.ResponseWriter, r *http.Request) {
	collectionName := "_CgsProject"
	db, err := server.Mongo()
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  err.Error(),
		})
		return
	}
	docs := bson.A{}
	opts := options.FindOptions{
		Sort: bson.M{
			"UpdateTime": -1,
		},
	}
	if server.Config.Authority.Enabled {
		user, _ := server.GetCurrentUser(r)
		if user != nil {
			filter1 := bson.M{
				"$or": bson.A{
					bson.M{
						"UserID": user.ID,
					},
					bson.M{
						"IsPublic": true,
					},
				},
			}
			if user.Name == "Administrator" {
				filter1 = bson.M{
					"$or": bson.A{
						filter1,
						bson.M{
							"UserID": bson.M{
								"$exists": 0,
							},
						},
					},
				}
			}
			db.FindMany(collectionName, filter1, &docs, &opts)
		} else { // no login user can see public scenes
			filter1 := bson.M{
				"IsPublic": true,
			}
			db.FindMany(collectionName, filter1, &docs, &opts)
		}
	} else {
		db.FindAll(collectionName, &docs, &opts)
	}

	list := []CgsProj{}

	for _, i := range docs {
		doc := i.(primitive.D).Map()

		publishId := ""

		if doc["PublishId"] != nil {
			publishId = doc["PublishId"].(string)
		}
		parentId := ""
		if doc["ParentId"] != nil {
			parentId = doc["ParentId"].(primitive.ObjectID).Hex()
		}
		jsPath := ""
		if doc["JsPath"] != nil {
			jsPath = doc["JsPath"].(string)
		}
		filePath := ""
		if doc["FilePath"] != nil {
			filePath = doc["FilePath"].(string)
		}
		data := ""
		if doc["Data"] != nil {
			data = doc["Data"].(string)
		}
		isPublic := false
		if doc["IsPublic"] != nil {
			isPublic = doc["IsPublic"].(bool)
		}
		fileType := ""
		if doc["FileType"] != nil {
			fileType = doc["FileType"].(string)
		}

		proj := CgsProj{
			ID:         doc["ID"].(primitive.ObjectID),
			Name:       doc["Name"].(string),
			Public: &isPublic,
			ParentId:   parentId,
			Data:       data,
			JsPath:     jsPath,
			FilePath:   filePath,
			UpdateTime: doc["UpdateTime"].(primitive.DateTime).Time(),
			PublishId:  publishId,
			FileType:   fileType,
		}
		list = append(list, proj)

	}

	helper.WriteJSON(w, server.Result{
		Code: 200,
		Msg:  "Get Successfully!",
		Data: list,
	})

}

// Delete delete a scene.
func Delete2(w http.ResponseWriter, r *http.Request) {
	collectionName := "_CgsProject"
	r.ParseForm()
	id, err := primitive.ObjectIDFromHex(r.FormValue("ID"))
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "ID is not allowed.",
		})
		return
	}

	db, err := server.Mongo()
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  err.Error(),
		})
		return
	}

	filter := bson.M{
		"ID": id,
	}

	doc := bson.M{}
	find, _ := db.FindOne(collectionName, filter, &doc)

	if !find {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "The project is not existed.",
		})
		return
	}

	// delete scene summary
	db.DeleteOne(collectionName, filter)

	helper.WriteJSON(w, server.Result{
		Code: 200,
		Msg:  "Delete successfully!",
	})
}

func ChangeData2(w http.ResponseWriter, r *http.Request) {

	collectionName := "_CgsProject"
	r.ParseForm()
	id, err := primitive.ObjectIDFromHex(strings.TrimSpace(r.FormValue("ID")))
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "Name is not allowed to be empty.",
		})
		return
	}

	publishId := strings.TrimSpace(r.FormValue("PublishId"))
	data := strings.TrimSpace(r.FormValue("Data"))
	now := time.Now()
	//save file to /Upload/Cgs/$ID/timestap.js
	fileName := fmt.Sprintf("%v.js", helper.TimeToString(now, "yyyyMMddHHmmss"))
	savePath := fmt.Sprintf("/Upload/Cgs/%v", id.Hex())
	filePath := fmt.Sprintf("%v/%v", savePath, fileName)
	physicalPath := server.MapPath(savePath)

	if _, err := os.Stat(physicalPath); os.IsNotExist(err) {
		os.MkdirAll(physicalPath, 0755)
	}
	target, err := os.Create(fmt.Sprintf("%v/%v", physicalPath, fileName))
	defer target.Close()
	if err != nil {

	} else {
		_, err = target.WriteString(data)
	}

	db, err := server.Mongo()
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  err.Error(),
		})
		return
	}
	filter := bson.M{
		"ID": id,
	}
	doc := bson.M{}
	find, _ := db.FindOne(collectionName, filter, &doc)

	if !find {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "Can not find project with ID " + id.String(),
		})
		return
	} else {
		if server.Config.Authority.Enabled {
			user, _ := server.GetCurrentUser(r)
			// save other people's scene
			if doc["UserID"] != nil && doc["UserID"].(string) != user.ID {
				helper.WriteJSON(w, server.Result{
					Code: 300,
					Msg:  "Permission denied.",
				})
				return
			}
			// not admin save scene without UserID
			if doc["UserID"] == nil && user.RoleName != "Administrator" {
				helper.WriteJSON(w, server.Result{
					Code: 300,
					Msg:  "Permission denied.",
				})
				return
			}
		}

		set := bson.M{
			"Data":       data,
			"JsPath":     filePath,
			"FilePath":   filePath,
			"UpdateTime": now,
		}

		if publishId != "" {
			set["PublishId"] = publishId
		}

		update := bson.M{
			"$set": set,
		}
		db.UpdateOne(collectionName, filter, update)

	}

	helper.WriteJSON(w, server.Result{
		Code: 200,
		Msg:  "Saved successfully!",
	})

}

func ChangeName2(w http.ResponseWriter, r *http.Request) {
	collectionName := "_CgsProject"
	r.ParseForm()
	id, err := primitive.ObjectIDFromHex(strings.TrimSpace(r.FormValue("ID")))
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  err.Error(),
		})
		return
	}
	name := strings.TrimSpace(r.FormValue("Name"))

	if name == "" {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "Name is not allowed to be empty.",
		})
		return
	}
	if strings.HasPrefix(name, "_") {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "Name is not allowed to start with _.",
		})
		return
	}
	now := time.Now()

	ispublic := strings.TrimSpace(r.FormValue("Public"))
	ifPublic := false
	if ispublic == "on" {
		ifPublic = true
	}
	db, err := server.Mongo()
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  err.Error(),
		})
		return
	}
	filter := bson.M{
		"ID": id,
	}
	doc := bson.M{}
	find, _ := db.FindOne(collectionName, filter, &doc)

	if !find {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "Can not find project with ID " + id.String(),
		})
	} else {
		if server.Config.Authority.Enabled {
			user, _ := server.GetCurrentUser(r)
			// save other people's scene
			if doc["UserID"] != nil && doc["UserID"].(string) != user.ID {
				helper.WriteJSON(w, server.Result{
					Code: 300,
					Msg:  "Permission denied.",
				})
				return
			}
			// not admin save scene without UserID
			if doc["UserID"] == nil && user.RoleName != "Administrator" {
				helper.WriteJSON(w, server.Result{
					Code: 300,
					Msg:  "Permission denied.",
				})
				return
			}
		}
		update := bson.M{
			"$set": bson.M{
				"Name":       name,
				"IsPublic":   ifPublic,
				"UpdateTime": now,
			},
		}
		db.UpdateOne(collectionName, filter, update)

	}

	helper.WriteJSON(w, server.Result{
		Code: 200,
		Msg:  "Saved successfully!",
	})

}

func Save2(w http.ResponseWriter, r *http.Request) {

	collectionName := "_CgsProject"
	r.ParseForm()
	id, err := primitive.ObjectIDFromHex(strings.TrimSpace(r.FormValue("ID")))
	if err != nil {
		id = primitive.NewObjectID()
	}
	name := strings.TrimSpace(r.FormValue("Name"))
	ispublic := strings.TrimSpace(r.FormValue("Public"))
	ifPublic := false
	if ispublic == "on" {
		ifPublic = true
	}

	fmt.Println(ispublic)
	if name == "" {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "Name is not allowed to be empty.",
		})
		return
	}
	if strings.HasPrefix(name, "_") {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "Name is not allowed to start with _.",
		})
		return
	}
	data := strings.TrimSpace(r.FormValue("Data"))
	now := time.Now()
	//save file to /Upload/Cgs/$ID/timestap.js
	fileName := fmt.Sprintf("%v.js", helper.TimeToString(now, "yyyyMMddHHmmss"))
	savePath := fmt.Sprintf("/Upload/Cgs/%v", id.Hex())
	filePath := fmt.Sprintf("%v/%v", savePath, fileName)
	physicalPath := server.MapPath(savePath)

	if _, err := os.Stat(physicalPath); os.IsNotExist(err) {
		os.MkdirAll(physicalPath, 0755)
	}
	target, err := os.Create(fmt.Sprintf("%v/%v", physicalPath, fileName))
	defer target.Close()
	if err != nil {

	} else {
		_, err = target.WriteString(data)
	}

	db, err := server.Mongo()
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  err.Error(),
		})
		return
	}
	filter := bson.M{
		"ID": id,
	}
	doc := bson.M{}
	find, _ := db.FindOne(collectionName, filter, &doc)

	if !find {
		doc = bson.M{
			"ID":         id,
			"Name":       name,
			"Data":       data,
			"JsPath":     filePath,
			"FilePath":   filePath,
			"CreateTime": now,
			"UpdateTime": now,
			"IsPublic":   ifPublic,
		}
		if server.Config.Authority.Enabled {
			user, _ := server.GetCurrentUser(r)
			if user != nil {
				doc["UserID"] = user.ID
			}
		}
		db.InsertOne(collectionName, doc)
	} else {
		if server.Config.Authority.Enabled {
			user, _ := server.GetCurrentUser(r)
			// save other people's scene
			if doc["UserID"] != nil && doc["UserID"].(string) != user.ID {
				helper.WriteJSON(w, server.Result{
					Code: 300,
					Msg:  "Permission denied.",
				})
				return
			}
			// not admin save scene without UserID
			if doc["UserID"] == nil && user.RoleName != "Administrator" {
				helper.WriteJSON(w, server.Result{
					Code: 300,
					Msg:  "Permission denied.",
				})
				return
			}
		}
		update := bson.M{
			"$set": bson.M{
				"Data":       data,
				"JsPath":     filePath,
				"UpdateTime": now,
			},
		}
		db.UpdateOne(collectionName, filter, update)

	}

	helper.WriteJSON(w, server.Result{
		Code: 200,
		Msg:  "Saved successfully!",
	})

}

func Get2(w http.ResponseWriter, r *http.Request) {
	collectionName := "_CgsProject"
	id, err := primitive.ObjectIDFromHex(strings.TrimSpace(r.FormValue("ID")))
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  "ID is not allowed to be empty.",
		})
		return
	}
	db, err := server.Mongo()
	if err != nil {
		helper.WriteJSON(w, server.Result{
			Code: 300,
			Msg:  err.Error(),
		})
		return
	}
	doc := bson.M{}

	threeDCollectionName := server.CgsPortalVisualCollectionName + "ThreeD"
	filter1 := bson.M{
		"$and": bson.A{
			bson.M{
				"Status": 1,
			},
			bson.M{
				"ProjectID": id,
			},
		},
	}

	find, _ := db.FindOne(threeDCollectionName, filter1, &doc)
	filter1 = bson.M{"ID": id}
	if !find {
		//find by user id and id
		user, _ := server.GetCurrentUser(r)
		if user == nil {
			helper.WriteJSON(w, server.Result{
				Code: 301,
				Msg:  "Not Allowed",
			})
		}
		filter1 = bson.M{
			"$and": bson.A{
				filter1,
				bson.M{
					"UserID": user.ID,
				},
			},
		}
	}

	db.FindOne(collectionName, filter1, &doc)

	//if server.Config.Authority.Enabled {
	//	user, _ := server.GetCurrentUser(r)
	//	if user != nil {
	//		filter1 := bson.M{
	//			"$or": bson.A{
	//				bson.M{
	//					"UserID": user.ID,
	//				},
	//				bson.M{
	//					"IsPublic": true,
	//				},
	//			},
	//		}
	//		filter1 = bson.M{
	//			"$and": bson.A{
	//				filter1,
	//				bson.M{
	//					"ID": id,
	//				},
	//			},
	//		}
	//		db.FindOne(collectionName, filter1, &doc)
	//	} else { // no login user can see public scenes
	//		filter1 := bson.M{
	//			"IsPublic": true,
	//			"ID":       id,
	//		}
	//
	//		db.FindOne(collectionName, filter1, &doc)
	//	}
	//}

	//publishId := ""
	//if doc["PublishId"] != nil {
	//	publishId = doc["PublishId"].(string)
	//}
	//parentId := ""
	//if doc["ParentId"] != nil {
	//	parentId = doc["ParentId"].(primitive.ObjectID).Hex()
	//}
	//jsPath := ""
	//if doc["JsPath"] != nil {
	//	jsPath = doc["JsPath"].(string)
	//}
	filePath := ""
	if doc["FilePath"] != nil {
		filePath = doc["FilePath"].(string)
	}
	//data := ""
	//if doc["Data"] != nil {
	//	data = doc["Data"].(string)
	//}
	//isPublic := false
	//if doc["IsPublic"] != nil {
	//	isPublic = doc["IsPublic"].(bool)
	//}
	//fileType := ""
	//if doc["FileType"] != nil {
	//	fileType = doc["FileType"].(string)
	//}

	publishId := ""
	if doc["PublishId"] != nil {
		publishId = doc["PublishId"].(string)
	}

	proj := CgsProj{
		ID:   doc["ID"].(primitive.ObjectID),
		Name: doc["Name"].(string),
		//Public:   isPublic,
		//ParentId: parentId,
		//Data:       data,
		//JsPath:     jsPath,
		FilePath: filePath,
		//UpdateTime: doc["UpdateTime"].(primitive.DateTime).Time(),
		PublishId:  publishId,
		//FileType:   fileType,
	}

	helper.WriteJSON(w, server.Result{
		Code: 200,
		Msg:  "Get Successfully!",
		Data: proj,
	})
}
